package jinyilw.swing.visuals.panel;

import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;

public class PositionProducer
{
	private int maxCol = 30; // 最大列
	protected int W = 90; // 宽
	protected int H = 80; // 高
	protected int S = 6; // 间距
	protected int upB = 6; // 上边距
	protected int leftB = 12; // 左边距

	private final ArrayList<Position> positions = new ArrayList<>();
	private final ArrayList<PositionSetter> positionSetters = new ArrayList<>();
	private int width, minLeftB;

	public PositionProducer()
	{
	}

	public PositionProducer(int maxCol)
	{
		this.maxCol = maxCol;
	}

	public void setParameter(int ww, int hh, int ss)
	{
		W = ww;
		H = hh;
		S = ss;
	}

	public void setParameter(int ww, int hh, int ss, int up, int left)
	{
		W = ww;
		H = hh;
		S = ss;
		upB = up;
		leftB = left;
	}

	public void setMaxColumn(int maxCol)
	{
		if (this.maxCol == maxCol)
			return;
		this.maxCol = maxCol;
		int i = 0;
		for (Position p : positions)
		{
			p.setPosition(i / maxCol, i % maxCol);
			i++;
		}
	}

	public void updateMaxColumn(int maxCol, boolean force)
	{
		if (this.maxCol == maxCol && !force)
			return;
		this.maxCol = maxCol;
		int i = 0;
		for (Position p : positions)
		{
			p.setPosition(i / maxCol, i % maxCol);
			i++;
		}
		for (PositionSetter setter : positionSetters)
			setter.updatePosition();
	}

	public void updateParameter(int ww, int hh, int ss)
	{
		updateParameter(ww, hh, ss, upB, leftB, maxCol);
	}

	public void updateParameter(int ww, int hh, int ss, int up, int left)
	{
		updateParameter(ww, hh, ss, up, left, maxCol);
	}

	public void updateParameter(int ww, int hh, int ss, int up, int left, int maxCol)
	{
		W = ww;
		H = hh;
		S = ss;
		upB = up;
		leftB = left;
		if (this.maxCol != maxCol)
		{
			this.maxCol = maxCol;
			int i = 0;
			for (Position p : positions)
			{
				p.setPosition(i / maxCol, i % maxCol);
				i++;
			}
		} else
			for (Position p : positions)
				p.update();
		for (PositionSetter setter : positionSetters)
			setter.updatePosition();
	}

	public void calculateMaxColumn(int width, int minLeftB)
	{
		if (this.width == width && this.minLeftB == minLeftB)
			return;
		this.width = width;
		this.minLeftB = leftB = minLeftB;
		int col = (width - minLeftB - minLeftB) / (W + S);
		if (col < 1)
			col = 1;
		else
			leftB = minLeftB + (width - col * (W + S) - S) / 2;

		updateMaxColumn(col, true);
	}

	public synchronized void addPositionSetter(PositionSetter setter)
	{
		if (setter != null)
		{
			setter.setPosition(getPosition(positionSetters.size()));
			positionSetters.add(setter);
		}
	}

	public void removePositionSetter(PositionSetter setter)
	{
		removePositionSetter(positionSetters.indexOf(setter));
	}

	public synchronized void removePositionSetter(int index)
	{
		int size = positionSetters.size();
		if (index >= 0 && index < size)
		{
			for (int i = index + 1; i < size; i++)
				positionSetters.get(i).setPosition(positions.get(i - 1));
			positionSetters.remove(index);
		}
	}

	public void removeAllPositionSetter()
	{
		positionSetters.clear();
	}

	public synchronized Position getPosition(int index)
	{
		int size = positions.size();
		if (index == size)
		{
			Position p = new Position(this, index / maxCol, index % maxCol);
			positions.add(p);
			return p;
		}
		if (index >= 0 && index < size)
			return positions.get(index);
		int n = index - size;
		if (n > 0 && n < 30)
		{
			for (int i = size; i <= index; i++)
				positions.add(new Position(this, i / maxCol, i % maxCol));
			return positions.get(index);
		}
		return new Position(this, index / maxCol, index % maxCol);
	}

	public Position getNewPosition()
	{
		return getPosition(positions.size());
	}

	public Position getPosition(int row, int col)
	{
		return getPosition(row * maxCol + col);
	}

	public Position createPosition()
	{
		return new Position(this);
	}

	public Position createPosition(int row, int col)
	{
		return new Position(this, row, col);
	}

	public Point getPoint(int row, int col)
	{
		return new Point((W + S) * col + leftB, (H + S) * row + upB);
	}

	public int getIndex(int x, int y)
	{
		int row = (y - upB) / (H + S);
		int col = (x - leftB) / (W + S);
		if (row >= 0 && col >= 0)
			return row * maxCol + col;
		return -1;
	}

	public int getMaxColumn()
	{
		return maxCol;
	}

	public int getMaxRow()
	{
		int maxIndex = positionSetters.size() - 1;
		if (maxIndex > 0)
			return positions.get(maxIndex).getRow() + 1;
		return 1;
	}

	public Dimension getPreferredSize()
	{
		int width = leftB + (W + S) * maxCol - S + leftB;
		int height;
		int maxIndex = positionSetters.size() - 1;
		if (maxIndex > 0)
			height = positions.get(maxIndex).getY() + H + leftB;
		else
			height = H + upB + leftB;
		return new Dimension(width, height);
	}

	public int getPreferredWidth()
	{
		return leftB + (W + S) * maxCol - S + leftB;
	}

	public int getPreferredHeight()
	{
		int maxIndex = positionSetters.size() - 1;
		if (maxIndex > 0)
			return positions.get(maxIndex).getY() + H + leftB;
		return H + upB + leftB;
	}

	public int getW()
	{
		return W;
	}

	public int getH()
	{
		return H;
	}

	public int getS()
	{
		return S;
	}

	public int getUpB()
	{
		return upB;
	}

	public int getLeftB()
	{
		return leftB;
	}
}
